package cn.chess.controller;

import cn.chess.WxPayDomain.OrderInfo;
import cn.chess.WxPayDomain.OrderReturnInfo;
import cn.chess.WxPayDomain.SignInfo;
import cn.chess.domain.Orders;
import cn.chess.service.OrderService;
import cn.chess.util.*;
import com.thoughtworks.xstream.XStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

import static cn.chess.util.WXConst.title;


@RestController
@RequestMapping(value = "/api/v1")
public class WXPayController {

    @Autowired
    private OrderService orderService;
    /**
     * 下单
     */
    @PostMapping(value = "/weixin/payment")
    public Map payment(@RequestBody String oid ) {

        String orderid = oid.substring(oid.indexOf(":")+2, oid.lastIndexOf("\""));

        Map<String, Object> map = new HashMap<>();


        try {
            OrderInfo orderInfo = orders2orderInfo(orderid);


            String result = HttpRequest.sendPost(WXConst.pay_url, orderInfo);
            System.out.println(result);
            XStream xStream = new XStream();
            xStream.alias("xml", OrderReturnInfo.class);

            OrderReturnInfo returnInfo = (OrderReturnInfo) xStream.fromXML(result);
            // 二次签名
            if ("SUCCESS".equals(returnInfo.getReturn_code()) && returnInfo.getReturn_code().equals(returnInfo.getResult_code())) {
                SignInfo signInfo = new SignInfo();
                signInfo.setAppId(WXConst.appId);
                long time = System.currentTimeMillis() / 1000;
                signInfo.setTimeStamp(String.valueOf(time));
                signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
                signInfo.setRepay_id("prepay_id=" + returnInfo.getPrepay_id());
                signInfo.setSignType("MD5");
                //生成签名
                String sign1 = Signature.getSign(signInfo);
                Map<String, String> payInfo = new HashMap<>();
                payInfo.put("timeStamp", signInfo.getTimeStamp());
                payInfo.put("nonceStr", signInfo.getNonceStr());
                payInfo.put("package", signInfo.getRepay_id());
                payInfo.put("signType", signInfo.getSignType());
                payInfo.put("paySign", sign1);
                map.put("status", 200);
                map.put("msg", "统一下单成功!");
                map.put("data", payInfo);

                // 此处可以写唤起支付前的业务逻辑

                // 业务逻辑结束 回传给小程序端唤起支付
                return map;
            }
            map.put("status", 500);
            map.put("msg", "统一下单失败!");
            map.put("data", null);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 微信小程序支付成功回调函数
     */
    @RequestMapping(value = "/weixin/callback")
    public void wxNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) request.getInputStream()));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        //sb为微信返回的xml
        String notityXml = sb.toString();
        String resXml = "";
        System.out.println("接收到的报文：" + notityXml);

        Map map = PayUtil.doXMLParse(notityXml);

        String returnCode = (String) map.get("return_code");
        if ("SUCCESS".equals(returnCode)) {
            //验证签名是否正确
            Map<String, String> validParams = PayUtil.paraFilter(map);  //回调验签时需要去除sign和空值参数
            String validStr = PayUtil.createLinkString(validParams);//把数组所有元素，按照“参数=参数值”的模式用“&”字符拼接成字符串
            String sign = PayUtil.sign(validStr, WXConst.key, "utf-8").toUpperCase();//拼装生成服务器端验证的签名
            // 因为微信回调会有八次之多,所以当第一次回调成功了,那么我们就不再执行逻辑了

            //根据微信官网的介绍，此处不仅对回调的参数进行验签，还需要对返回的金额与系统订单的金额进行比对等
            if (sign.equals(map.get("sign"))) {
                /**此处添加自己的业务逻辑代码start**/
                // bla bla bla....
                /**此处添加自己的业务逻辑代码end**/
                //通知微信服务器已经支付成功
                resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                        + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml> ";
            } else {
                System.out.println("微信支付回调失败!签名不一致");
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
        }
        System.out.println(resXml);
        System.out.println("微信支付回调数据结束");

        BufferedOutputStream out = new BufferedOutputStream(
                response.getOutputStream());
        out.write(resXml.getBytes());
        out.flush();
        out.close();
    }

    public OrderInfo orders2orderInfo(String orderId) {


        Orders orders = orderService.getOrderByOrderid(orderId);
        int money = yuan2Fen(orders.getPrice().toPlainString());
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setAppid(WXConst.appId);
        orderInfo.setMch_id(WXConst.mch_id);
        orderInfo.setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
        orderInfo.setBody(title);
//        orderInfo.setOut_trade_no(RandomStringGenerator.getRandomStringByLength(32));
        orderInfo.setTotal_fee(money);     // 该金钱其实10 是 0.1元
        orderInfo.setSpbill_create_ip("127.0.0.1");
        orderInfo.setNotify_url(WXConst.notify_url);
        orderInfo.setTrade_type(WXConst.TRADETYPE);
        //这里直接使用当前用户的openid
        orderInfo.setOpenid(orders.getOpenid());
        orderInfo.setSign_type(WXConst.SIGNTYPE);
        orderInfo.setOut_trade_no(orders.getOid());
        //生成签名
        String sign = null;
        try {
            sign = Signature.getSign(orderInfo);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        orderInfo.setSign(sign);
        return orderInfo;
    }
    /**
     * 将单位为元的金额转换为单位为分
     *
     * @param yuan 单位为元的字符型值
     * @return
     */
    public  int yuan2Fen(String yuan) {
        int value = 0;

        try {
            BigDecimal var1 = new BigDecimal(yuan);
            BigDecimal var2 = new BigDecimal(100);
            BigDecimal var3 = var1.multiply(var2);
            value = Integer.parseInt(var3.stripTrailingZeros().toPlainString());
        } catch (Exception e) {
            throw new IllegalArgumentException(String.format("非法金额[%s]", yuan));
        }

        Assert.isTrue(value >= 0, String.format("非法金额[%s]", yuan));
        return value;
    }


}
